/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package simhya.dataprocessing;
import java.util.ArrayList;

/**
 *
 * @author Luca
 */
public class SingleStochasticTrajectoryCollector implements DataCollector {
    private ArrayList<String> variableHeaders;
    //specialized saving not implemented yet
    private ArrayList<Integer> variablesToBeSaved;
    private double timeStep;
    private boolean saveInitialState;
    //burnout period to be implemented
    private double initialSavingTime;
    private Trajectory trajectory;
    private double lastPrintTime;
    private boolean initialized;

    public SingleStochasticTrajectoryCollector() {
        this.timeStep = 1;
        init();
    }

    public SingleStochasticTrajectoryCollector(double timeStep) {
        this.timeStep = timeStep;
        init();
    }

    private void init() {
        this.variableHeaders = null;
        this.variablesToBeSaved = null;
        this.saveInitialState = true;
        this.initialSavingTime = 0;
        lastPrintTime = 0;
        initialized = false;
    }



    public void setTimeStep(double time) {
        this.timeStep  = time;
    }

    public void setVariablesHeader(ArrayList<String> names) {
        this.variableHeaders = names;
        this.trajectory = new Trajectory(names);
        initialized = true;
    }

  

    /**
     * @param nextTime next simulation time
     * @return true if there is the need to save samples during a simulation step
     */
    public boolean dataNeeded(double nextTime) {
        if (nextTime > this.lastPrintTime + this.timeStep)
            return true;
        else return false;
    }

    /**
     * Adds one or more points to the trajectory
     * @param values
     * @param nextTime
     */
    public void putData(double[] values, double nextTime) {
        while (this.lastPrintTime + this.timeStep < nextTime) {
            lastPrintTime += timeStep;
            trajectory.add(lastPrintTime, extractVariables(values));
        }
    }

    /**
     * Saves the initial state to the trajectory
     * @param values
     * @param time
     */
    public void putInitialState(double[] values, double time) {
        if (!this.initialized)
            throw new DataException("Data collector not initialized properly");
        if (this.saveInitialState)
            this.trajectory.add(time, extractVariables(values));
        this.lastPrintTime = time;
    }

    /**
     * Saves the final state to the trajectory
     * @param values
     * @param time
     */
    public void putFinalState(double[] values, double time) {
        this.trajectory.add(time, extractVariables(values));
    }

    /**
     * Extracts the subset of variables specified in the proper command
     * @param vars
     * @return
     */
    private double[] extractVariables(double[] vars) {
        if (this.variablesToBeSaved == null)
            return vars;
        int c = 0;
        double[] v = new double[this.variablesToBeSaved.size()];
        for (Integer i : this.variablesToBeSaved)
            v[c++] = vars[i];
        return v;
    }


    /**
     *
     * @return the trajectory stored in the data collector.
     */
    public Trajectory getTrajectory() {
        return this.trajectory;
    }


    /**
     * Replaces the current trajectory
     */
    public void newTrajectory() {
        this.trajectory = new Trajectory(this.variableHeaders);
        lastPrintTime = 0;
    }

    /**
     *
     * @return the next time at which a time point needs to be saved
     */
    public double nextTimeOfDataPoint() {
        return this.lastPrintTime + this.timeStep;
        
    }

    /**
     * Puts the next data point in the trajectory. To be used by continuous output mechanisms
     * @param values
     */
    public void putData(double[] values) {
        lastPrintTime += timeStep;
        trajectory.add(lastPrintTime, extractVariables(values));
    }

}
